/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.StateInvariant;

import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.FrameEditPart;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseBestCoveredCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.figures.SeDiSubpartFigure;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CoverCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.LifelinePosition;
import com.cea.papyrus.diagram.sequence.sedi.model.command.SetConstraintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.SetOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.diagram.SetBoundsHintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles layout of StateInvariants.
 * 
 * @author frankd@ifi.uio.no
 */
public class StateInvariantLayoutHandler extends InteractionFragmentLayoutHandler {

    @SuppressWarnings("unchecked")
    public Rectangle layout(final Diagram diagram, final StateInvariant si) {
        // TODO Calculate horizontal position
        GraphNode siView = ModelUtil.getGraphNode(si, diagram);

        if (!si.getCovereds().isEmpty()) {
            Lifeline lifeline = (Lifeline) si.getCovereds().get(0);
            GraphNode lifelineView = ModelUtil.getGraphNode(lifeline, diagram);
            Rectangle lifeBounds =
                    new Rectangle(lifelineView.getPosition(), lifelineView.getSize());
            // TODO Find a vertical position on the lifeline, or WARN if not able
            // TODO Query figure for preferred position
            return new Rectangle(lifeBounds.getCenter().x, siView.getPosition().y, 1, 1);
        } else
            // TODO query figure for default position
            return new Rectangle(100, 100, 1, 1);
    }

    @SuppressWarnings("unchecked")
    public Command[] getMoveCommands(final EditPart fragmentPart, final Rectangle suggestedBounds) {

        final List<Command> cmds = new LinkedList<Command>();

        final GraphNode fragmentView = (GraphNode) fragmentPart.getModel();

        final SeDiSubpartFigure fragmentFigure =
                (SeDiSubpartFigure) ((GraphicalEditPart) fragmentPart).getFigure();

        final InteractionFragment fragment =
                ModelUtil.<InteractionFragment> getSemantic(fragmentView);

        // SetConstraintCommand
        // Move the lifeline
        // AnalyseCoveredByCommand
        // CoveredByCommand
        // Moving the fragment may have brought a different set of
        // lifelines beneath it.

        // Step 1
        // TODO Remove the SetConstraintCommand.
        // It is currently needed because the Analyse-command below
        // uses coordinates fetched from the model to perform its analysis
        // Then it needs the new coordinates to produce correct result.
        final Rectangle preferredBounds = fragmentFigure.getPreferredBounds(suggestedBounds);
        final Command boundsCmd = new SetConstraintCommand(fragmentView, preferredBounds);

        final SetBoundsHintCommand hintCmd = new SetBoundsHintCommand();
        hintCmd.setHint(preferredBounds);

        // Step 2
        Point locationAbs = preferredBounds.getLocation().getCopy();
        fragmentFigure.translateToAbsolute(locationAbs);

        final AnalyseOwnerCommand ownerCmd = new AnalyseOwnerCommand();
        ownerCmd.setDiagram(LookForElement.getDiagram(fragmentView));
        ownerCmd.setAnyEditPart(fragmentPart);
        ownerCmd.setLocation(locationAbs);

        final SetOwnerCommand setOwnerCmd = new SetOwnerCommand();
        setOwnerCmd.setFragment(fragment);
        // glue0: owner

        final AnalyseBestCoveredCommand analyseCoveredCmd = new AnalyseBestCoveredCommand();
        analyseCoveredCmd.setInteractionEditPart((FrameEditPart) fragmentPart.getParent());
        analyseCoveredCmd.setFragmentNode(fragmentView);

        final CoverCommand coverCmd = new CoverCommand();
        coverCmd.setFragment(fragment);

    	if (!isDetachedFromLifeline()) {
    		
        	LifelinePosition coveredLifelinePosition = 
        		new LifelinePosition(fragment.getCovereds().get(0), 0);
        	List<LifelinePosition>  lifelinePositions = 
        		new ArrayList<LifelinePosition>();
        	lifelinePositions.add(coveredLifelinePosition);
        	coverCmd.setCovered(lifelinePositions);
        	
    	}
    	
        Command glue1 = new Command() {
            public void execute() {
                setOwnerCmd.setOwner(ownerCmd.getOwner());
            }
        };

        Command glue2 = new Command() {
            public void execute() {
            	
            	if (isDetachedFromLifeline()) {
            		coverCmd.setCovered(analyseCoveredCmd.getCovered());	
            	}
            }
        };

        cmds.add(ownerCmd);
        cmds.add(glue1);
        cmds.add(setOwnerCmd);
        cmds.add(boundsCmd);
        cmds.add(hintCmd);
        cmds.add(analyseCoveredCmd);
        cmds.add(glue2);
        cmds.add(coverCmd);

        return cmds.toArray(new Command[cmds.size()]);
    }
}
